#include "stdafx.h"
#include "GameEngine.h"
#include "DXDevice.h"
#include "../Meshes/ModelLib.h"

// Static variabele
GameEngine* GameEngine::m_GameEnginePtr = NULL;

// GameEngine Functions
GameEngine::GameEngine(): m_GamePtr(0), m_AppPaused(false), 
	m_Width(1024), m_Height(768), m_OldTime(0)
{
	Logger::GetSingleton();
}

GameEngine::~GameEngine()
{
	delete Logger::GetSingleton();
}

GameEngine* GameEngine::GetSingleton()
{
	if ( m_GameEnginePtr == NULL) m_GameEnginePtr = new GameEngine();
	return m_GameEnginePtr;
}

void GameEngine::SetGame(AbstractGame* gamePtr)
{
	m_GamePtr = gamePtr;
}

bool GameEngine::Run(HINSTANCE hInstance, int iCmdShow)
{
	MSG msg;
	bool Quit = false;

	// no singleton == no start
	if(GameEngine::GetSingleton() == NULL) return false;

	m_hInstance = hInstance;

	if(FAILED(CreateNewWindow(iCmdShow)))
	{
		MessageBox(NULL, _T("ERROR Creating window."), _T("ERROR"), MB_OK);
		return false;
	}

	// Create DXDevice
	if(FAILED(DXDevice::GetSingleton()->Init()))
	{
		MessageBox(NULL, _T("Error Creating DirectX Device."), _T("ERROR"), MB_OK);
		return false;
	}

	// Init Game
	m_GamePtr->Init();

	while(!Quit)
	{
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if(msg.message == WM_QUIT) break;
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}else{
			if(!Quit)
			{
				if(m_AppPaused) Sleep(20); else
				{
					DWORD nu = timeGetTime();
					float dif = (nu - m_OldTime) / 1000.0f;
					if(dif > 0.3f) dif = 0.3f;
					m_OldTime = timeGetTime();

					DXDevice::GetSingleton()->Tick(dif);
					m_GamePtr->Tick(dif);
					DXDevice::GetSingleton()->Render();
				}
			}
		}
	}
	return msg.wParam?true:false;
}

HRESULT GameEngine::CreateNewWindow(int cmdShow)
{
	WNDCLASSEX    wndclass;

	// Create the window class for the main window
	wndclass.cbSize         = sizeof(WNDCLASSEX);
	wndclass.style          = CS_CLASSDC;
	wndclass.lpfnWndProc    = WndProc;
	wndclass.cbClsExtra     = 0;
	wndclass.cbWndExtra     = 0;
	wndclass.hInstance      = m_hInstance;
	wndclass.hIcon          = 0;
	wndclass.hIconSm        = 0;
	wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground  = NULL; // (HBRUSH)(COLOR_WINDOW + 1);
	wndclass.lpszMenuName   = NULL;
	wndclass.lpszClassName  = _T("GameEngine");

	// Register the window class
	if (!RegisterClassEx(&wndclass))
	{
		MessageBox(0, _T("RegisterClass FAILED"), 0, 0);

		return E_FAIL;
	}
	// Default to a window with a client area rectangle of m_iWidth x m_iHeight
	RECT R = {0, 0, m_Width, m_Height};
	AdjustWindowRect(&R, WS_OVERLAPPEDWINDOW, false);
 
	// Create the window
	m_hWindow = CreateWindow(	_T("GameEngine"), 
		_T("GameEngine"), 
		WS_OVERLAPPED | WS_SYSMENU , 
		CW_USEDEFAULT, CW_USEDEFAULT, 
		R.right,R.bottom, 
		NULL, NULL, 
		m_hInstance, NULL);
	if (!m_hWindow)	
	{
		MessageBox(0, _T("CreateWindow FAILED"), 0, 0);
		return E_FAIL;
	}
	// Show and update the window
	ShowWindow(m_hWindow, SW_SHOWDEFAULT);
	UpdateWindow(m_hWindow);

	return S_OK;
}

HWND GameEngine::GetWindow() const
{
	return m_hWindow;
}

LRESULT GameEngine::HandleEvent(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;
	// Route Windows messages to game engine member functions
	switch (msg)
	{
	// WM_ACTIVE is sent when the window is activated or deactivated.
	// We pause the game when the main window is deactivated and 
	// unpause it when it becomes active.
	case WM_ACTIVATE:
		if( LOWORD(wParam) == WA_INACTIVE )
			m_AppPaused = true;
		else
			m_AppPaused = false;
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(m_hWindow, &ps);
		EndPaint(m_hWindow, &ps);
		break;

	case WM_CREATE:
		// Set the game window 
		m_hWindow = hWindow;
		// Seed the random number generator
		srand(GetTickCount());
		return 0;

	case WM_DESTROY:
		// End the game and post quit message, so it gets in de main message loop. 
		DXDevice::GetSingleton()->Cleanup();
		PostQuitMessage(0);
		return 0;
	case WM_KEYDOWN:
		m_GamePtr->KeyPressed(wParam);
		return 0;
	case WM_ENTERSIZEMOVE:
		m_AppPaused = true;
		break;
	case WM_EXITSIZEMOVE:
		DXDEVICE->OnResize();
		m_AppPaused = false;
		break;
	default:
		break;

	}
	return DefWindowProc(hWindow, msg, wParam, lParam);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	return GameEngine::GetSingleton()->HandleEvent(hWnd, msg, wParam, lParam);
}

AbstractGame* GameEngine::GetGame() const
{
	return m_GamePtr;
}

int GameEngine::GetWidth() const
{
	RECT rc;
	GetClientRect(GetWindow(), &rc);

	return rc.right - rc.left;
}

int GameEngine::GetHeight() const
{
		RECT rc;
	GetClientRect(GetWindow(), &rc);

	return rc.bottom - rc.top;
}

HINSTANCE GameEngine::GetInstance() const
{
	return m_hInstance;
}